﻿using MXERP.Shared.Exceptions;
using MXERP.Shared.Extensions;
using System.ComponentModel;
using System.Data;
using System.Reflection;

namespace MXERP.Shared.Extensions
{
    public static class DataTableExtension
    {
        public static DataTable ToDataTable<T>(this IEnumerable<T> data)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            var table = new DataTable();
            foreach (PropertyDescriptor prop in properties)
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            foreach (T item in data)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                table.Rows.Add(row);
            }
            return table;
        }
        public static T? ToEntity<T>(this DataTable dt) where T : new()
        {
            IEnumerable<T> entities = dt.ToCollection<T>();
            return entities.FirstOrDefault();
        }
        public static List<T> ToList<T>(this DataTable dt) where T : new()
        {
            IEnumerable<T> entities = dt.ToCollection<T>();
            return entities.ToList();
        }
        public static IEnumerable<T> ToCollection<T>(this DataTable dt) where T : new()
        {
            if (dt == null || dt.Rows.Count == 0)
            {
                return Enumerable.Empty<T>();
            }
            IList<T> ts = new List<T>();
            foreach (DataRow dr in dt.Rows)
            {
                T t = new();
                PropertyInfo[] propertys = t.GetType().GetProperties();
                foreach (PropertyInfo pi in propertys)
                {
                    string tempName = pi.Name;
                    //检查DataTable是否包含此列（列名==对象的属性名）     
                    if (dt.Columns.Contains(tempName))
                    {
                        // 判断此属性是否有Setter   
                        if (!pi.CanWrite) continue;//该属性不可写，直接跳出   
                        object value = dr[tempName];
                        if (value != DBNull.Value)
                            SetValue(pi, t, value);
                    }
                }
                ts.Add(t);
            }
            return ts;
        }

        private static void SetValue<T>(PropertyInfo pi, T t, object value)
        {
            string obj = value == null ? "" : value.ToString()!.Trim();
            string type = pi.PropertyType.ToString();
            if (type.Contains("System.String"))
            {
                pi.SetValue(t, obj, null);
            }
            else if (type.Contains("System.DateTime"))
            {
                DateTime dateV;
                if (double.TryParse(obj, out double doubleV))
                {
                    dateV = DateTime.FromOADate(doubleV);
                }
                else
                {
                    if (!DateTime.TryParse(obj, out dateV))
                    {
                        throw new ApiException($"请填写时间格式");
                    }
                }
                pi.SetValue(t, dateV, null);
            }
            else if (type.Contains("System.Boolean"))
            {
                if (!bool.TryParse(obj, out bool boolV))
                {
                    throw new ApiException($"请填写true或者false");
                }
                pi.SetValue(t, boolV, null);
            }
            else if (type.Contains("System.Int"))
            {
                if (!int.TryParse(obj, out int intV) || obj.Contains('.'))
                {
                    throw new ApiException($"请填写整数");
                }
                pi.SetValue(t, intV, null);
            }
            else if (type.Contains("System.Byte"))
            {
                _ = byte.TryParse(obj, out byte v);
                pi.SetValue(t, v, null);
            }
            else if (type.Contains("System.Decimal"))
            {
                if (!decimal.TryParse(obj, out decimal v))
                {
                    throw new ApiException($"请填写数字");
                }
                pi.SetValue(t, v, null);
            }
            else if (type.Contains("System.Double"))
            {
                if (!double.TryParse(obj, out double v))
                {
                    throw new ApiException($"请填写数字");
                }
                pi.SetValue(t, v, null);
            }
            else
            {
                pi.SetValue(t, value, null);
            }
        }
    }
}
